package com.brillilab.starter.controller.aio.register;

import com.aliyun.openservices.shade.org.apache.commons.lang3.StringUtils;
import com.brillilab.common.alioss.OssUtils;
import com.brillilab.common.constant.ResultEnum;
import com.brillilab.common.entity.ResponseVo;
import com.brillilab.common.utils.MyBeanUtils;
import com.brillilab.common.utils.ValidatorUtil;
import com.brillilab.domain.enums.lab.LabAuditStateEnum;
import com.brillilab.domain.enums.lab.LabMemberEnum;
import com.brillilab.domain.po.lab.Lab;
import com.brillilab.domain.po.lab.LabApply;
import com.brillilab.domain.po.lab.LabMember;
import com.brillilab.domain.po.user.Users;
import com.brillilab.domain.vo.apply.LabInfoVo;
import com.brillilab.domain.vo.apply.MobilCodeVo;
import com.brillilab.domain.vo.common.KeyValue;
import com.brillilab.domain.vo.lab.CheckEmailCodeVo;
import com.brillilab.domain.vo.lab.LabApplyInfoVo;
import com.brillilab.domain.vo.lab.LabApplyVo;
import com.brillilab.domain.vo.user.UserRegVo;
import com.brillilab.service.core.email.impl.EmailServiceImpl;
import com.brillilab.service.core.lab.ILabApplyService;
import com.brillilab.service.core.lab.ILabMemberService;
import com.brillilab.service.core.lab.ILabService;
import com.brillilab.service.core.lab.IOrganizationService;
import com.brillilab.service.core.system.IDictService;
import com.brillilab.service.core.user.IInviteCodeService;
import com.brillilab.service.core.user.IUsersService;
import com.brillilab.service.logic.crm.CrmUsersLogic;
import com.brillilab.service.logic.lab.LabApplyLogic;
import com.brillilab.service.logic.message.MessageLogic;
import com.brillilab.service.logic.user.UserInviteAuditLogic;
import com.brillilab.service.logic.user.UsersLogic;
import com.brillilab.starter.aspect.AspectLog;
import com.brillilab.starter.entity.req.lab.SmsSendReq;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.io.UnsupportedEncodingException;
import java.util.*;

/**
 * @author zlb
 * @Title: ApplyLabController
 * @ProjectName brill_lab
 * @Description: 申请创建实验室相关
 * @date 2019/7/3 9:27
 */
@Slf4j
@RestController
@RequestMapping("/api/applyLab")
public class ApplyRegLabController {

    @Resource
    private MessageLogic messageLogic;
    @Resource
    private LabApplyLogic labApplyLogic;
    @Resource
    private ILabApplyService labApplyService;
    @Resource
    private IDictService dictService;
    @Resource
    private CrmUsersLogic crmUsersLogic;
    @Resource
    private OssUtils ossUtil;
    @Resource
    private UsersLogic usersLogic;
    @Resource
    private EmailServiceImpl emailService;
    @Resource
    private IUsersService usersService;
    @Resource
    private ILabMemberService labMemberService;
    @Resource
    private ILabService labService;
    @Resource
    private IOrganizationService organizationService;
    @Resource
    private UserInviteAuditLogic userInviteAuditLogic;
    @Resource
    private IInviteCodeService inviteCodeService;

    /**
     * 发送验证码
     *
     * @param smsSendReq
     * @return
     */
    @PostMapping("/regSendCode")
    public ResponseVo regSendCode(@RequestBody SmsSendReq smsSendReq) {
        String mobile = smsSendReq.getMobile();
        Assert.isTrue(StringUtils.isNotBlank(mobile), "请输入手机号！");
        Users user = usersLogic.getUser(mobile.trim());
        if (user != null) {
            //申请注册实验室，需判断用户是否存在
            Assert.isTrue(smsSendReq.getLabId() != null, "您已经注册过此系统了，快去客户端登录查看吧！");
            //邀请注册时，判断实验室是否为当前手机号所在实验室
            if (smsSendReq.getLabId() != null && smsSendReq.getLabId() > 0) {
                boolean isHaveLab = labApplyLogic.CheckPIUser(user);
                Assert.isTrue(isHaveLab, "此用户已经是PI，无法加入其它实验室！");

                if (user.getLabId() != null && user.getLabId() > 0) {
                    ResponseVo failure;
                    //用户存在，且在当前实验室
                    LabMember labMember = labMemberService.selectMember(smsSendReq.getLabId(), user.getId());
                    if (labMember != null && LabMemberEnum.State.STATE_IN.getValue().equals(labMember.getState())) {
                        //提示已加入当前实验室
                        failure = ResponseVo.failure(ResultEnum.USER_EXIST_CURRENT_LAB.getMessage());
                        failure.setCode(ResultEnum.USER_EXIST_CURRENT_LAB.getCode());
                        return failure;
                    }
                }
            }
        }

        KeyValue<Integer, String> keyValue = null;
        //申请实验室逻辑验证
        if (smsSendReq.getLabId() == null) {
            keyValue = labApplyLogic.checkUserState(mobile);
        }
        if (keyValue == null) {
            UserRegVo userVo = null;
            if (user != null) {
                userVo = new UserRegVo();
                BeanUtils.copyProperties(user, userVo);
                userVo.setTips("此用户已注册，请填写信息后加入实验室");
                List<LabMember> labMembers = labMemberService.selectAllByUserId(user.getId());
                if (labMembers != null && labMembers.size() > 0) {
                    labMembers.sort(Comparator.comparing(LabMember::getUpdateTime).reversed());
                    LabMember labMember = labMembers.get(0);
                    userVo.setDutyName(labMember.getDuty());
                    Map<Integer, String> userDutyMap = dictService.getUserDutyMap();
                    if (userDutyMap != null) {
                        for (Map.Entry<Integer, String> entry : userDutyMap.entrySet()) {
                            Integer mapKey = entry.getKey();
                            String mapValue = entry.getValue();
                            if (mapValue.equals(labMember.getDuty())) {
                                userVo.setDuty(mapKey);
                            }
                        }
                    }
                }
            }
            return messageLogic.sendVerifyCode(mobile, 300) ? ResponseVo.success(userVo, "验证码已发送,请注意查收") : ResponseVo.failure("发送短信失败！");
        } else {
            LabApply labApply = labApplyService.selectUser(mobile, null);
            LabApplyVo labApplyVo = MyBeanUtils.copyBean(labApply, LabApplyVo.class);
            return ResponseVo.failure(ResultEnum.FAILURE, keyValue.getValue(), labApplyVo);
        }
    }

    /**
     * 校验验证码
     *
     * @param mobilCodeVo
     * @return
     */
    @PostMapping("/checkSmsCode")
    public ResponseVo checkSmsCode(@RequestBody MobilCodeVo mobilCodeVo) {
        String mobile = mobilCodeVo.getMobile();
        String code = mobilCodeVo.getCode();
        Assert.isTrue(StringUtils.isNotBlank(mobile), ResultEnum.REQUEST_PARAM_LACK.getMessage());
        Assert.isTrue(StringUtils.isNotBlank(code), ResultEnum.REQUEST_PARAM_LACK.getMessage());
        Assert.isTrue(ValidatorUtil.isPhone(mobile), "手机号格式错误");
        return messageLogic.checkVerifyCode(mobile, code) ? ResponseVo.success() : ResponseVo.failure("短信验证失败！");
    }

    /**
     * 检测手机号是否存在实验室
     *
     * @param mobile
     * @return
     */
    @GetMapping("/checkIsHaveLab")
    public ResponseVo checkIsHaveLab(String mobile) {
        Assert.isTrue(StringUtils.isNotBlank(mobile), ResultEnum.REQUEST_PARAM_LACK.getMessage());
        Assert.isTrue(ValidatorUtil.isPhone(mobile), "手机号格式错误");
        return labApplyLogic.checkIsHaveLab(mobile);
    }

    /**
     * 检测手机号/邮箱是否存在实验室
     *
     * @param checkType  检测类型（1手机号，2邮箱）
     * @param checkValue
     * @return
     */
    @GetMapping("/checkIsExistLab")
    public ResponseVo checkIsExistLab(Integer checkType, String checkValue) {
        Assert.notNull(checkType, "检测类型不能为空");
        Assert.isTrue(!StringUtils.isEmpty(checkValue), "检测值不能为空");
        if (checkType == 1) {
            //检测手机号
            Assert.isTrue(StringUtils.isNotBlank(checkValue), "手机号不能为空");
            Assert.isTrue(ValidatorUtil.isPhone(checkValue), "手机号格式错误");
            return labApplyLogic.checkIsHaveLab(checkValue);
        } else if (checkType == 2) {
            //检测邮箱
            Assert.isTrue(StringUtils.isNotBlank(checkValue), "邮箱不能为空");
            Assert.isTrue(ValidatorUtil.isEmail(checkValue), "邮箱格式错误");
            boolean isRightEmail = labApplyLogic.checkEmailFormat(checkValue);
            Assert.isTrue(isRightEmail, "非学术机构邮箱，禁止提交申请！");
            return labApplyLogic.checkEmailIsHaveLab(checkValue);
        }
        return ResponseVo.failure("检测类型有误！");
    }

    /**
     * 检测实验室名称是否重复
     *
     * @param labInfo
     * @return
     */
    @PostMapping("/checkLabName")
    public ResponseVo checkLabName(@RequestBody LabInfoVo labInfo) {
        Assert.notNull(labInfo, ResultEnum.REQUEST_PARAM_LACK.getMessage());
        Assert.isTrue(StringUtils.isNotBlank(labInfo.getLabName()), "实验室名称不能为空");
        Assert.isTrue(StringUtils.isNotBlank(labInfo.getOrgName()), "一级机构名称不能为空");
        Assert.isTrue(StringUtils.isNotBlank(labInfo.getSecOrgName()), "二级机构不能为空");

        Lab lab = labService.selectByLabNameAndOrgName(labInfo.getLabName().trim(), labInfo.getOrgName().trim(), labInfo.getSecOrgName().trim());
        Assert.isNull(lab, "当前实验室名称已存在，建议您换一个名称");
        return ResponseVo.success();
    }

    /**
     * 提交申请实验室信息
     *
     * @param applyInfoVo
     * @return
     */
    @AspectLog
    @PostMapping("/submitApply")
    public ResponseVo submitApply(@RequestBody LabApplyInfoVo applyInfoVo) {
        Assert.isTrue(StringUtils.isNotEmpty(applyInfoVo.getMobile()), "手机号不能为空！");
        Assert.isTrue(ValidatorUtil.isPhone(applyInfoVo.getMobile()), "手机号格式错误");
        Assert.isTrue(StringUtils.isNotEmpty(applyInfoVo.getPassword()), "密码不能为空！");
        Assert.isTrue(StringUtils.isNotEmpty(applyInfoVo.getLabName()), "实验室名称不能为空！");
        Assert.isTrue(applyInfoVo.getLabName().length() <= 50, "实验室名称参数字符过长！");
        Assert.isTrue(StringUtils.isNotBlank(applyInfoVo.getInviteCode()), "邀请码不能为空！");
        Assert.isTrue(inviteCodeService.checkInviteCode(applyInfoVo.getInviteCode()), "邀请码无效！");
        Assert.isTrue(applyInfoVo.getIsOwner() != null, "参数【isOwner】缺失！");
        Assert.isTrue(applyInfoVo.getOrgId() != null && !applyInfoVo.getOrgId().equals(0), "机构ID参数有误！");
        Assert.isTrue(StringUtils.isNotEmpty(applyInfoVo.getOrgName()), "机构单位不能为空！");
        Assert.isTrue(StringUtils.isNotEmpty(applyInfoVo.getSecOrgName()), "二级机构不能为空！");
        Assert.isTrue(StringUtils.isNotEmpty(applyInfoVo.getRealName()), "姓名不能为空！");
        Assert.isTrue(applyInfoVo.getRealName().length() <= 50, "姓名参数字符过长！");
        Assert.isTrue(StringUtils.isNotEmpty(applyInfoVo.getSecurityPwd()), "数据密码不能为空！");


        //通过所传参数，判断是否为帮PI申请
        if (StringUtils.isNotEmpty(applyInfoVo.getPiMobile())) {
            //PI手机号非空，表示为帮PI申请
            applyInfoVo.setIsOwner(0);
        }
        if (applyInfoVo.getIsOwner().equals(0)) {
            Assert.isTrue(StringUtils.isNotEmpty(applyInfoVo.getPiMobile()), "PI手机号不能为空！");
            Assert.isTrue(ValidatorUtil.isPhone(applyInfoVo.getPiMobile()), "PI手机号格式有误");
            Assert.isTrue(StringUtils.isNotEmpty(applyInfoVo.getPiRealName()), "PI姓名不能为空！");
            Assert.isTrue(StringUtils.isNotEmpty(applyInfoVo.getPiEmail()), "PI机构邮箱不能为空！");
            Assert.isTrue(ValidatorUtil.isEmail(applyInfoVo.getPiEmail()), "PI机构邮箱格式有误");

            Users user = usersLogic.getUser(applyInfoVo.getPiMobile().trim());
            Assert.isNull(user, "此PI手机号已注册过此系统了！");

            boolean isRightEmail = labApplyLogic.checkEmailFormat(applyInfoVo.getPiEmail());
            Assert.isTrue(isRightEmail, "PI邮箱必须为学术机构邮箱！");
        }

        if (applyInfoVo.getLabType() == null) {
            //实验室默认为科研机构
            applyInfoVo.setLabType(1);
        }
        if (applyInfoVo.getLabType() == 2) {
            //企业注册判断项
            if (StringUtils.isNotEmpty(applyInfoVo.getRealId())) {
                Assert.isTrue(StringUtils.isNotEmpty(applyInfoVo.getCardFront()), "请输入身份证正面照！");
                Assert.isTrue(StringUtils.isNotEmpty(applyInfoVo.getCardReverse()), "请输入身份证反面照！");
            }
            if (StringUtils.isNotEmpty(applyInfoVo.getCardFront()) == true || StringUtils.isNotEmpty(applyInfoVo.getCardReverse()) == true) {
                Assert.isTrue(StringUtils.isNotEmpty(applyInfoVo.getRealId()), "请输入身份证号码！");
            }

            Assert.isTrue(StringUtils.isNotEmpty(applyInfoVo.getCompanyName()), "请输入企业名称！");
            Assert.isTrue(StringUtils.isNotEmpty(applyInfoVo.getOfficialLetter()), "请上传布理岚柏认证申请公函！");
            Assert.isTrue(StringUtils.isNotEmpty(applyInfoVo.getBusinessLicence()), "请上传营业执照！");
            Assert.isTrue(StringUtils.isNotEmpty(applyInfoVo.getCreditCode()), "请输入统一社会信用代码！");
        }

        Lab lab = labService.selectByLabNameAndOrgInfo(applyInfoVo.getLabName().trim(), applyInfoVo.getOrgId(), applyInfoVo.getSecOrgName().trim());
        Assert.isNull(lab, "当前实验室名称已存在，建议您换一个名称");

        if (applyInfoVo.getIsOwner() == 0) {
            //检测PI手机号
            if (StringUtils.isNotBlank(applyInfoVo.getPiMobile())) {
                Users userPI = usersLogic.getUser(applyInfoVo.getPiMobile());
                Assert.isTrue(labApplyLogic.CheckPIUser(userPI), "此PI手机号已有实验室！");
            }
        } else {
            //PI手机号检测是否有实验室
            Users userPI = usersLogic.getUser(applyInfoVo.getMobile());
            Assert.isTrue(labApplyLogic.CheckPIUser(userPI), "此PI手机号已有实验室！");
        }
        //机构邮箱验证码检测
        if (StringUtils.isNotEmpty(applyInfoVo.getOrgEmail())) {
            String orgEmail = applyInfoVo.getOrgEmail();
            Assert.isTrue(ValidatorUtil.isEmail(orgEmail), "请输入正确格式的邮箱！");
            boolean isRightEmail = labApplyLogic.checkEmailFormat(orgEmail);
            Assert.isTrue(isRightEmail, "非学术机构邮箱，禁止提交申请！");
        }

        LabApply labApply = labApplyLogic.submitLabApply(applyInfoVo);
        if (labApply != null && labApply.getId() > 0) {
            if (labApply.getState().equals(LabAuditStateEnum.AUDIT_PASS.getValue())) {
                return ResponseVo.success("您已成功申请了实验室，请您在客户端登录。", "您已成功申请了实验室，请您在客户端登录。");
            } else if (labApply.getState().equals(LabAuditStateEnum.WAIT_CHECK.getValue())) {
                return ResponseVo.success("验证信息已经发送到您的邮箱，请您在邮箱中点击链接验证", "验证信息已经发送到您的邮箱，请您在邮箱中点击链接验证");
            } else if (labApply.getState().equals(LabAuditStateEnum.WAIT_AUDIT.getValue())) {
                // code 2001 前端界面需要
                return ResponseVo.failure(ResultEnum.LAB_NO_PI_OR_LAB_AUDIT_WAIT_PC, "您的申请已经提交成功！我们会在1—3个工作日内审核完成，审核完成后会短信通知您，请您耐心等待。", null);
            } else {
                return ResponseVo.failure("状态异常:" + labApply.getState());
            }
        } else {
            return ResponseVo.failure("提交申请失败");
        }
    }


    /**
     * 检测邮箱验证码
     *
     * @param checkEmailCodeVo
     * @return
     */
    @PostMapping("/checkEmailCode")
    public boolean checkEmailCode(@RequestBody CheckEmailCodeVo checkEmailCodeVo) {
        String email = checkEmailCodeVo.getEmail();
        String validateCode = checkEmailCodeVo.getValidateCode();
        Assert.isTrue(StringUtils.isNotBlank(validateCode), "请输验证码！");
        return messageLogic.checkEmailVerifyCode(email, validateCode.trim());
    }


    /**
     * 申请实验室邮箱验证
     *
     * @return
     */
    @GetMapping("/checkRegCode")
    public ResponseVo checkRegCode(String checkCode) {
        String decodeStr = null;
        try {
            decodeStr = new String(Base64.getUrlDecoder().decode(checkCode), "utf-8");
        } catch (UnsupportedEncodingException e) {
            log.info("验证码---》" + checkCode + " base64解密失败");
        }
        String[] array = decodeStr.split("_");
        Assert.isTrue(array.length == 3, ResultEnum.REQUEST_PARAM_LACK.getMessage());
        Integer checkType = Integer.parseInt(array[0]);//验证类型（1申请实验室，2申请加入实验室）
        Long id = Long.parseLong(array[1]);
        String code = array[2];
        Assert.isTrue(StringUtils.isNotBlank(code), ResultEnum.REQUEST_PARAM_LACK.getMessage());
        if (checkType.equals(1)) {
            //检测申请实验室验证码
            return labApplyLogic.checkLabApplyCode(id, code);
        } else {
            //检测申请加入实验室验证码
            return userInviteAuditLogic.checkApplyJoinLabCode(id, code);
        }
    }

    /**
     * 注册邀请码验证
     *
     * @return
     */
    @GetMapping("/checkInviteCode")
    public ResponseVo checkRegInviteCode(String inviteCode) {
        Assert.isTrue(StringUtils.isNotBlank(inviteCode), "邀请码不能为空！");
        String tips = "";
        boolean isSuccess = true;
        if (!inviteCodeService.checkInviteCode(inviteCode.trim())) {
            isSuccess = false;
            tips = "请填写有效的邀请码";
        }
        Map<String, Object> result = new HashMap<>();
        result.put("tips", tips);
        result.put("isSuccess", isSuccess);
        return ResponseVo.success(result, "Success");
    }

}

